package org.darkforest.common.services.impl;

import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.darkforest.common.services.*;
import org.darkforest.common.util.AliOssFileUploadUtil;
import org.darkforest.common.util.DateUtil;
import org.darkforest.common.util.QRCodeUtil;
import org.darkforest.common.wxpay.utils.ClientCustomSSL;
import org.darkforest.common.wxpay.utils.Signature;
import org.darkforest.dao.mapper.OrderGoodsMapper;
import org.darkforest.dao.mapper.OrderMapper;
import org.darkforest.enums.SettingNameEnum;
import org.darkforest.enums.VariablePrefixEnum;
import org.darkforest.model.*;
import org.darkforest.vo.PayInfoVo;
import org.darkforest.vo.WxUserDetailInfo;
import org.darkforest.vo.WxUserInfo;
import org.darkforest.common.wxpay.payutils.MD5Util;
import org.darkforest.common.wxpay.payutils.Sha1Util;
import org.darkforest.common.wxpay.utils.HttpTool;
import org.darkforest.common.wxpay.utils.XMLUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by valentina on 15/7/12.
 */
@Service
public class WxJSSdkServiceImpl implements WxJSSdkService {


    private static Logger logger = LoggerFactory.getLogger(WxJSSdkServiceImpl.class);
    @Autowired
    private SettingService settingService;
    @Autowired
    private SimpleRedisService redisService;
    @Autowired
    private RefundReturnService refundReturnService;
    @Autowired
    private OrderPayService orderPayService;
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderGoodsMapper orderGoodsMapper;

    /**
     *  通过code 取得access_token 和 openid
     * @param code
     * @return
     */
    @Override
    public WxUserInfo getUserAccessToken(String code) {
        WxUserInfo userInfo = new WxUserInfo();
//        if(userInfo==null){
        String returnJSON = HttpTool.getToken(settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID), settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_SECRET), "authorization_code", code);
        JSONObject obj = JSONObject.fromObject(returnJSON);
        System.out.println(obj);
        userInfo.setAccess_token(obj.getString("access_token"));
        userInfo.setOpenid(obj.getString("openid"));
        userInfo.setExpires_in(obj.getInt("expires_in"));
        userInfo.setRefresh_token(obj.getString("refresh_token"));
        userInfo.setScope(obj.getString("scope"));

        return userInfo;
    }
    public WxUserInfo getQYUserAccessToken(String code) {
        WxUserInfo userInfo = new WxUserInfo();

        String appid = settingService.getSettingInfo(SettingNameEnum.WXCORPID);
        String appsecret = settingService.getSettingInfo(SettingNameEnum.WXCORPSECRET);

        // 取得access_token 和 openid
        String returnJSON  = HttpTool.getQyToken(appid, appsecret, code);
        JSONObject obj = JSONObject.fromObject(returnJSON);
        System.out.println(obj);

        userInfo.setAccess_token(obj.getString("access_token"));
        userInfo.setOpenid(obj.getString("openid"));

        return userInfo;
    }

    /**
     * 微信端分享用
     * 获取微信签名 用jssdk的接口参数
     *
     * @param noncestr  //     * @param ticket
     * @param url
     * @param timeStamp
     * @return
     * @throws Exception
     */
    public String getJsSignature(String noncestr, String url, String timeStamp, String inMode) throws Exception {
        SortedMap<String, String> map = new TreeMap<String, String>();
        String access_token = this.getAccessToken(inMode);
        map.put("jsapi_ticket", getJsapiTicket(access_token, inMode));
        map.put("noncestr", noncestr);
        map.put("timestamp", timeStamp);
        map.put("url", url);
        return Sha1Util.createSHA1Sign(map);
    }

    public void sendWechatMessage(String openId, String text) {
        String param = "{\"touser\":\"" + openId + "\",\n" +
                "    \"msgtype\":\"text\",\n" +
                "    \"text\":{\n" +
                "    \"content\":\"" + text + "\"}\n" +
                "}";
        try {
            String access_token = getAccessToken("weixin");
            String result = HttpTool.sendPostMessage("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + access_token, param, "UTF-8");
            System.out.println(result);
            System.out.println("成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getMemberQRImg(String memberId, String avatar, String tmpDir) {
        String url = VariablePrefixEnum.QR_DIR_PRE.getKey_pre() + "/code_" + memberId + ".jpg";
        String avatarPath = null;
        String img_path = null;
        String redis_url = redisService.getByKey("QR_url_" + memberId);
        logger.debug("======member:" + memberId + ",===qr_url in redis:" + redis_url);
        if (redis_url == null) {
            try {
                //获取access_token
                String access_token = getAccessToken("weixin");
                //根据access_token获取ticket
                String param = "{" +
                        "    \"expire_seconds\": 604800, " +
                        "    \"action_name\": \"QR_SCENE\", " +
                        "    \"action_info\": {" +
                        "        \"scene\": {" +
                        "            \"scene_id\": " + memberId +
                        "        }" +
                        "    }" +
                        "}";
                String[] ticketInfo = HttpTool.sendJsonParamPost("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + access_token, param, new String[]{"ticket", "url", "expire_seconds"}, "UTF-8");
                Long expire_seconds = Long.parseLong(ticketInfo[2]);
                String content = ticketInfo[1];
//                url =
//                logger.debug(ticketInfo.length+",ticked:"+ticketInfo[0]+",url:"+url+",expire_seconds:"+expire_seconds);
//                logger.debug("url:"+url);

                //直接生成二维码图片并上传到阿里云服务器
                img_path = tmpDir + "code_" + memberId + ".jpg";
                if (StringUtils.isNotEmpty(avatar)) {

                    if (avatar != null && avatar.length() > 0 && avatar.indexOf("/0") > 0) {
                        avatar = avatar.substring(0, avatar.lastIndexOf("/"));
                    }
                    avatarPath = tmpDir + memberId + "_avatar";
                    //获取头像图片到本地
                    HttpTool.getRemoteFile(avatar + "/46", avatarPath);

                    //输出带logo的二维码
                    QRCodeUtil.encode(content, avatarPath, img_path, true);
                } else {
                    //头像为空时，直接生成二维码输出
                    try {
                        QRCodeUtil.encode(content, img_path);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                //上传二维码图片到阿里云服务器
//                logger.debug("-----"+AliOssFileUploadUtil.bucketName+","+AliOssFileUploadUtil.endPoint);
                AliOssFileUploadUtil.uploadQRcode(VariablePrefixEnum.QR_DIR_PRE.getKey_pre(), new File(img_path));
                redisService.setValueInTime("QR_url_" + memberId, url, expire_seconds);
            } catch (Exception e) {
                e.printStackTrace();
                //有异常出现时，返回空链接
                url = "";
            } finally {
                //删除临时二维码相关文件
                if (avatarPath != null) {
                    File local_avatar = new File(avatarPath);
                    local_avatar.delete();
                }
                if (img_path != null) {
                    File local_qrcode = new File(img_path);
                    local_qrcode.delete();
                }
            }
        }
        return url;
    }

    @Override
    public String getQRImgValidTime(Integer userId) {
        return redisService.getExpireTime(VariablePrefixEnum.QR_URL_PRE.getKey_pre() + userId);
    }

    /**
     * 微信退款
     *
     * @param refund
     * @return
     */
    @Override
    public boolean wxRefund(RefundReturn refund,Order od) {
        String refund_url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        String nonceStr = Sha1Util.getNonceStr();//随机字符串
        //组装参数
        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID));
        packageParams.put("mch_id", settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID));
        packageParams.put("nonce_str", nonceStr);

        OrderPay orderPay = orderPayService.selectByOrderSn(od.getOrderSn());
        BigDecimal total_fee = new BigDecimal("0.00");
        total_fee = total_fee.add(od.getOrderAmount());
//        Order odr = new Order();
//        odr.setOrderSn(od.getOrderSn());
//        odr.setBuyerId(od.getBuyerId());
//        List<Order> list = orderMapper.findOrderInfoByCondition(odr);
//        for (Order order : list) {
//            if (order.getPdAmount() != null && order.getPdAmount().compareTo(BigDecimal.ZERO) != 0) {
//                total_fee = total_fee.add(order.getOrderAmount().subtract(order.getPdAmount()));
//            } else {
//                total_fee = total_fee.add(od.getOrderAmount());
//            }
//        }

        packageParams.put("out_trade_no", orderPay.getPayOrderSn());
        packageParams.put("transaction_id", orderPay.getTransactionId());
        packageParams.put("out_refund_no", refund.getRefundSn() + "");
        if (od.getPdAmount() != null && od.getPdAmount().compareTo(BigDecimal.ZERO) != 0) {
            packageParams.put("refund_fee", refund.getRefundAmount().subtract(od.getPdAmount()).multiply(new BigDecimal(100)).intValue() + "");//转分
        } else {
            packageParams.put("refund_fee", refund.getRefundAmount().multiply(new BigDecimal(100)).intValue() + "");//转分
        }
        packageParams.put("total_fee", total_fee.multiply(new BigDecimal(100)).intValue() + ""); //转分
        packageParams.put("op_user_id", settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID));
        String sign = Signature.getSign(packageParams, settingService.getSettingInfo(SettingNameEnum.WXPAY_PARTNER_KEY));
        packageParams.put("sign", sign);

        try {
            Map call = ClientCustomSSL.call(refund_url, XMLUtil.ArrayToXml(packageParams), settingService.getSettingInfo(SettingNameEnum.WXPAY_REFUND_CERTIFICATE_PWD), settingService.getSettingInfo(SettingNameEnum.WXPAY_REFUND_CERTIFICATE_DIR));
            System.out.print(call);
            if ("SUCCESS".equals(call.get("result_code"))) {
                refund.setRefundState(3);
                refundReturnService.updateRefundReturn(refund);//修改微信退款状态
                Order order = orderMapper.selectByPrimaryKey(refund.getOrderId());
                order.setOrderState("0");
                order.setLockState(0);
                if (refund.getOrderAmount().compareTo(refund.getRefundAmount()) == 1) {
                    order.setRefundState(2);
                } else {
                    order.setRefundState(1);
                }
                orderMapper.updateByPrimaryKey(order);
                return true;
            } else {
                return false;
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.debug("" + e.getStackTrace());
            return false;
        }
    }

    /**
     * 微信扫码支付获取code_url
     *
     * @param order
     * @return
     */
    public Map<String, String> getWxScanPayUrl(OrderSearchBean order) throws Exception {

        String appId = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID);
        String mchtId = settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID);
        String notifyUrl = settingService.getSettingInfo(SettingNameEnum.WXPAY_NATIVE_NOTIFY_URL);
        String ip = settingService.getSettingInfo(SettingNameEnum.WXPAY_SPBILL_CREATE_IP);
        String native_type = settingService.getSettingInfo(SettingNameEnum.WXPAY_NATIVE_TYPE);
        String wx_pay_interface = settingService.getSettingInfo(SettingNameEnum.WXPAY_PAY_INTERFACE);
        String code_type = settingService.getSettingInfo(SettingNameEnum.WXPAY_INPUT_CHARSET);

        StringBuilder goodsName = new StringBuilder();
        for (OrderGoods orderGoods : order.getResultList().get(0).getGoods()) {
            goodsName.append(orderGoods.getGoodsName() + ",");
        }

//            String basePath = (String)request.getSession().getAttribute("basePath");
        String nonceStr = Sha1Util.getNonceStr();//随机字符串
//        String randomStr = (int)(Math.random()*1000)+"";
        // 接口package部分-内容----------------------------------------------------------
        TreeMap<String, String> contentMap = new TreeMap<String, String>();
        contentMap.put("appid", appId); // 公众账号 ID
        contentMap.put("mch_id", mchtId); // 商户号
//        contentMap.put("attach", ""); //附加数据原样返回
        contentMap.put("nonce_str", nonceStr); // 随机字符串
        contentMap.put("body", goodsName.substring(0, goodsName.length() - 1));
        contentMap.put("out_trade_no", order.getResultList().get(0).getOrderSn() + ""); // 商户订单号
        contentMap.put("total_fee", order.getResultList().get(0).getOrderAmount().multiply(new BigDecimal(100)).intValue() + ""); // 订单总金额
        contentMap.put("spbill_create_ip", ip); // 订单生成的机器IP
        contentMap.put("notify_url", notifyUrl); // 通知地址
        contentMap.put("trade_type", native_type); // 交易类型
        String wxpackage = createPackage(contentMap);
        contentMap.put("sign", wxpackage);

        String result = HttpTool.sendPost(wx_pay_interface, contentMap, code_type);
        Map<String, String> temp = XMLUtil.doXMLParse(result);//调用统一接口返回的值转换为XML格式

        if ("FAIL".equals(temp.get("result_code"))) {
            throw new Exception("订单参数异常");
        }

        Map<String, String> map = new HashMap<String, String>();
        map.put("code_url", temp.get("code_url"));
        map.put("order_sn", order.getOrderSn());
        map.put("fee", order.getResultList().get(0).getOrderAmount() + "");
        return map;
    }

    @Override
    public Map getJsApiPay(String code, String openid, OrderSearchBean order, String basePath) throws Exception {

        String appId = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID);
        String mchtId = settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID);
        String notifyUrl = settingService.getSettingInfo(SettingNameEnum.WXPAY_NOTIFY_URL);
        String signType = settingService.getSettingInfo(SettingNameEnum.WXPAY_SIGN_TYPE);
        String tradeJs = settingService.getSettingInfo(SettingNameEnum.WXPAY_TRADE_TYPE_JS);
        String ip = settingService.getSettingInfo(SettingNameEnum.WXPAY_SPBILL_CREATE_IP);


        StringBuilder goodsName = new StringBuilder();
        for (OrderGoods orderGoods : order.getResultList().get(0).getGoods()) {
            goodsName.append(orderGoods.getGoodsName() + ",");
        }

//            String basePath = (String)request.getSession().getAttribute("basePath");
        String nonceStr = Sha1Util.getNonceStr();//随机字符串
        String timeStamp = Sha1Util.getTimeStamp();//时间戳
//        String randomStr = (int)(Math.random()*1000)+"";
        // 接口package部分-内容----------------------------------------------------------
        TreeMap<String, String> contentMap = new TreeMap<String, String>();
        contentMap.put("appid", appId); // 公众账号 ID
        contentMap.put("mch_id", mchtId); // 商户号
        contentMap.put("nonce_str", nonceStr); // 随机字符串
        contentMap.put("body", goodsName.substring(0, goodsName.length() - 1));
//		contentMap.put("body",  CodeUtils.toUTF_8(goodsName.substring(0, goodsName.length() - 1))); // 商品描述
        contentMap.put("out_trade_no", order.getResultList().get(0).getOrderSn() + ""); // 商户订单号
        contentMap.put("total_fee", order.getResultList().get(0).getOrderAmount().multiply(new BigDecimal(100)).intValue() + ""); // 订单总金额
        contentMap.put("spbill_create_ip", ip); // 订单生成的机器IP
        contentMap.put("notify_url", notifyUrl); // 通知地址
        contentMap.put("trade_type", tradeJs); // 交易类型
        contentMap.put("openid", openid); // 用户标识
        String wxpackage = createPackage(contentMap);
        contentMap.put("sign", wxpackage);
        System.out.println(contentMap.toString() + "支付参数");
        String result = this.getPrepayId(contentMap);//调用统一接口返回的值
        Map<String, String> map = XMLUtil.doXMLParse(result);//调用统一接口返回的值转换为XML格式
        System.out.println(map);
        TreeMap<String, String> wxPayParamMap = new TreeMap<String, String>();
        wxPayParamMap.put("appId", appId);
        wxPayParamMap.put("nonceStr", nonceStr);
        wxPayParamMap.put("package", "prepay_id=" + map.get("prepay_id"));
        wxPayParamMap.put("signType", signType);
        wxPayParamMap.put("timeStamp", timeStamp);
        String paySign = createPaySign(wxPayParamMap);//支付得到的签名
        System.out.println("####生成的支付签名####paySign####" + paySign);
        wxPayParamMap.put("paySign", paySign);

        //获取signature
        String accessToken = getAccessToken("weixin");
        String ticket = getJsapiTicket(accessToken,"weixin");
        String signature = getSignature(ticket, settingService.getSettingInfo(SettingNameEnum.DOMAIN_NAME) + basePath + "/wxPay/doPay?showwxpaytitle=1&code=" + code + "&state=" + order.getResultList().get(0).getOrderSn(), nonceStr);

        System.out.println("########生成的signature########" + signature);

        wxPayParamMap.put("signature", signature);
        wxPayParamMap.put("orderId", order.getResultList().get(0).getOrderId() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("payMoney", order.getResultList().get(0).getOrderAmount() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("goodsName", order.getResultList().get(0).getGoods().get(0).getGoodsName());//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("orderSN", order.getResultList().get(0).getOrderSn() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("payOrderSN", order.getResultList().get(0).getOrderSn() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("storeName", order.getResultList().get(0).getStoreName());//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("goodsNum", order.getResultList().get(0).getGoods().get(0).getGoodsNum() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("goodsPrice", order.getResultList().get(0).getGoods().get(0).getGoodsPrice() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("goodsImg", order.getResultList().get(0).getGoods().get(0).getGoodsImage() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("buyerId", order.getResultList().get(0).getBuyerId() + "");//到前段显示使用，支付不需要此参数

        wxPayParamMap.put("notify_url", notifyUrl);

        return wxPayParamMap;
    }


    public synchronized boolean isWXSign(String TOKEN, String timestamp, String nonce, String signature) {
        String[] str = {TOKEN, timestamp, nonce};
        Arrays.sort(str); // 字典序排序
        String bigStr = str[0] + str[1] + str[2];

        String paysign = bigStr;
//		paysign = paysign.substring(0, paysign.length()-1);
        System.out.println("\n\n程序计算微信签名串：" + paysign);
        paysign = Sha1Util.getSha1(paysign);
        System.out.println("程序计算微信签名结果：" + paysign);
        System.out.println("微信返回签名结果：" + signature);
        if (paysign.equals(signature)) {
            System.out.println("DeBug微信签名比对结果：TRUE");
            return true;
        } else {
            System.out.println("DeBug微信签名比对结果：FALSE");
            return false;
        }
    }


    @Override
    public WxUserDetailInfo getUserDetail(String user_access_token, String openid) {
        WxUserDetailInfo userDetailInfo = new WxUserDetailInfo();
        String returnJson = HttpTool.getUserDetail(user_access_token, openid);
        JSONObject obj = JSONObject.fromObject(returnJson);
        logger.debug("===== 获取微信用户详细信息：" + returnJson + "=====");

        userDetailInfo.setOpenId(obj.getString("openid"));
        userDetailInfo.setNickName(obj.getString("nickname").replaceAll("[\\x{10000}-\\x{10FFFF}]", ""));
        userDetailInfo.setSex(Integer.parseInt(obj.getString("sex")));
        userDetailInfo.setLanguage(obj.getString("language"));
        userDetailInfo.setCity(obj.getString("city"));
        userDetailInfo.setProvince(obj.getString("province"));
        userDetailInfo.setCountry(obj.getString("country"));
        String avatar = obj.getString("headimgurl");
        if (avatar != null && avatar.length() > 0 && avatar.indexOf("/0") > 0) {
            avatar = avatar.substring(0, avatar.lastIndexOf("/"));
        }
        userDetailInfo.setAvatar(avatar);

        return userDetailInfo;
    }

    /**
     * web端微信扫码支付获取code_url
     *
     * @param
     * @return
     */
    public Map<String, String> getPCWxScanPayUrl(OrderVo orderVo, PayInfoVo payInfo) throws Exception {

        String appId = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID);
        String mchtId = settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID);
        String notifyUrl = settingService.getSettingInfo(SettingNameEnum.WXPAY_NATIVE_NOTIFY_URL);
        String ip = settingService.getSettingInfo(SettingNameEnum.WXPAY_SPBILL_CREATE_IP);
        String native_type = settingService.getSettingInfo(SettingNameEnum.WXPAY_NATIVE_TYPE);
        String wx_pay_interface = settingService.getSettingInfo(SettingNameEnum.WXPAY_PAY_INTERFACE);
        String code_type = settingService.getSettingInfo(SettingNameEnum.WXPAY_INPUT_CHARSET);

        StringBuilder goodsName = new StringBuilder();
        for (OrderGoods orderGoods : orderVo.getGoods()) {
            goodsName.append(orderGoods.getGoodsName() + ",");
        }

//            String basePath = (String)request.getSession().getAttribute("basePath");
        String nonceStr = Sha1Util.getNonceStr();//随机字符串
//        String randomStr = (int)(Math.random()*1000)+"";
        // 接口package部分-内容----------------------------------------------------------
        TreeMap<String, String> contentMap = new TreeMap<String, String>();
        contentMap.put("appid", appId); // 公众账号 ID
        contentMap.put("mch_id", mchtId); // 商户号
//        contentMap.put("attach", ""); //附加数据原样返回
        contentMap.put("nonce_str", nonceStr); // 随机字符串
        contentMap.put("body", goodsName.substring(0, goodsName.length() - 1));
        contentMap.put("out_trade_no", payInfo.getPayNo() + ""); // 商户订单号
        contentMap.put("total_fee", payInfo.getTotal_fee().multiply(new BigDecimal(100)).intValue() + ""); // 订单总金额
        contentMap.put("spbill_create_ip", ip); // 订单生成的机器IP
        contentMap.put("notify_url", notifyUrl); // 通知地址
        contentMap.put("trade_type", native_type); // 交易类型
        String wxpackage = createPackage(contentMap);
        contentMap.put("sign", wxpackage);

        String result = HttpTool.sendPost(wx_pay_interface, contentMap, code_type);
        Map<String, String> temp = XMLUtil.doXMLParse(result);//调用统一接口返回的值转换为XML格式

        if ("FAIL".equals(temp.get("result_code"))) {
            throw new Exception("订单参数异常");
        }
        String orderSns = "";
        List<Order> orders = orderMapper.getOrderByPayno(payInfo.getPayNo());
        for (Order order : orders) {
            orderSns += order.getOrderSn() + ",";
        }
        Map<String, String> map = new HashMap<String, String>();
        map.put("code_url", temp.get("code_url"));
        map.put("order_sn", orderSns);
        map.put("fee", payInfo.getTotal_fee() + "");
        return map;
    }

    /**
     * 生成微信充值支付数据
     *
     * @param openid
     * @param pdRecharge
     * @return
     * @throws Exception
     */
    @Override
    public Map getJsApiPayForRecharge(String openid, PdRecharge pdRecharge) throws Exception {
        String appId = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID);
        String mchtId = settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID);
        String notifyUrl = settingService.getSettingInfo(SettingNameEnum.WXPAY_NOTIFY_URL);
        String signType = settingService.getSettingInfo(SettingNameEnum.WXPAY_SIGN_TYPE);
        String tradeJs = settingService.getSettingInfo(SettingNameEnum.WXPAY_TRADE_TYPE_JS);
        String ip = settingService.getSettingInfo(SettingNameEnum.WXPAY_SPBILL_CREATE_IP);

        String goodsName = "充值";
        String nonceStr = Sha1Util.getNonceStr();//随机字符串
        String timeStamp = Sha1Util.getTimeStamp();//时间戳
        // 接口package部分-内容----------------------------------------------------------
        TreeMap<String, String> contentMap = new TreeMap<String, String>();
        contentMap.put("appid", appId); // 公众账号 ID
        contentMap.put("mch_id", mchtId); // 商户号
        contentMap.put("nonce_str", nonceStr); // 随机字符串
        contentMap.put("body", goodsName);
//		contentMap.put("body",  CodeUtils.toUTF_8(goodsName.substring(0, goodsName.length() - 1))); // 商品描述
        contentMap.put("out_trade_no", pdRecharge.getPdrSn() + ""); // 商户订单号
        contentMap.put("total_fee", pdRecharge.getPdrAmount().multiply(new BigDecimal(100)).intValue() + ""); // 订单总金额
        contentMap.put("spbill_create_ip", ip); // 订单生成的机器IP
        contentMap.put("notify_url", notifyUrl); // 通知地址
        contentMap.put("trade_type", tradeJs); // 交易类型
        contentMap.put("openid", openid); // 用户标识
        String wxpackage = createPackage(contentMap);
        contentMap.put("sign", wxpackage);
        System.out.println(contentMap.toString() + "支付参数");
        String result = this.getPrepayId(contentMap);//调用统一接口返回的值
        Map<String, String> map = XMLUtil.doXMLParse(result);//调用统一接口返回的值转换为XML格式
        System.out.println(map);
        TreeMap<String, String> wxPayParamMap = new TreeMap<String, String>();
        wxPayParamMap.put("appId", appId);
        wxPayParamMap.put("nonceStr", nonceStr);
        wxPayParamMap.put("package", "prepay_id=" + map.get("prepay_id"));
        wxPayParamMap.put("signType", signType);
        wxPayParamMap.put("timeStamp", timeStamp);
        String paySign = createPaySign(wxPayParamMap);//支付得到的签名
        System.out.println("####生成的支付签名####paySign####" + paySign);
        wxPayParamMap.put("paySign", paySign);

        //获取signature
        String accessToken = getAccessToken("weixin");
        String ticket = getJsapiTicket(accessToken,"weixin");
        //String signature = getSignature(ticket, settingService.getSettingInfo(SettingNameEnum.DOMAIN_NAME) + basePath + "/wxPay/doRecharge?showwxpaytitle=1&pdrId=" + pdRecharge.getPdrId(), nonceStr);
        String signature = getSignature(ticket,settingService.getSettingInfo(SettingNameEnum.WXPAY_PAY_SIGN_URL), nonceStr);

        System.out.println("########生成的signature########" + signature);

        wxPayParamMap.put("signature", signature);
        wxPayParamMap.put("pdrId", pdRecharge.getPdrId() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("pdrAmount", pdRecharge.getPdrAmount() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("goodsName", goodsName);//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("pdrSn", pdRecharge.getPdrSn() + "");//到前段显示使用，支付不需要此参数
        wxPayParamMap.put("notify_url", notifyUrl);

        return wxPayParamMap;
    }

    /**
     *  js-sdk 支付
     * @param orderVos
     * @param openid
     * @param orderBatchNumber
     * @return
     * @throws Exception
     */
    public Map<String, String> getJsApiPayParams(List<OrderVo> orderVos, String openid, String orderBatchNumber) throws Exception {

        BigDecimal total_fee = new BigDecimal(0);
        for(OrderVo orderVo:orderVos){
            total_fee =  total_fee.add(orderVo.getOrderAmount());
        }

        String appId = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID);
        String mchtId = settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID);
        String notifyUrl = settingService.getSettingInfo(SettingNameEnum.WXPAY_NOTIFY_URL);
        String signType = settingService.getSettingInfo(SettingNameEnum.WXPAY_SIGN_TYPE);
        String tradeJs = settingService.getSettingInfo(SettingNameEnum.WXPAY_TRADE_TYPE_JS);
        String ip = settingService.getSettingInfo(SettingNameEnum.WXPAY_SPBILL_CREATE_IP);

        String nonceStr = Sha1Util.getNonceStr();//随机字符串
        String timeStamp = Sha1Util.getTimeStamp();//时间戳
        List<OrderGoods> orderGoodsList = new ArrayList<OrderGoods>();
        StringBuffer sbf = new StringBuffer();
        for(OrderVo orderVo:orderVos){
            orderGoodsList.addAll(orderGoodsMapper.findOrderGoodsListByOrderId(orderVo.getOrderId())) ;

            for (OrderGoods orderGoods : orderGoodsList) {
                sbf.append(orderGoods.getGoodsName());
                sbf.append(",");
            }
        }

        // 接口package部分-内容----------------------------------------------------------
        TreeMap<String, String> contentMap = new TreeMap<String, String>();
        contentMap.put("appid", appId); // 公众账号 ID
        contentMap.put("mch_id", mchtId); // 商户号
        contentMap.put("nonce_str", nonceStr); // 随机字符串
        if(orderGoodsList.size()>1){
            contentMap.put("body", orderGoodsList.get(0).getGoodsName()+"……");
        }else if(orderGoodsList.size()==1){
            contentMap.put("body", orderGoodsList.get(0).getGoodsName());
        }else{
            contentMap.put("body", "goods");
        }
        contentMap.put("out_trade_no", orderBatchNumber+ getRandom()); // 商户订单号
        contentMap.put("total_fee", total_fee.multiply(new BigDecimal(100)).intValue() + ""); // 订单总金额
        contentMap.put("spbill_create_ip", ip); // 订单生成的机器IP
        contentMap.put("notify_url", notifyUrl); // 通知地址
        contentMap.put("trade_type", tradeJs); // 交易类型
        contentMap.put("openid", openid); // 用户标识
        String wxpackage = createPackage(contentMap);
        contentMap.put("sign", wxpackage);
        System.out.println(contentMap.toString() + "支付参数");
        logger.info("======支付参数:" + contentMap.toString());
        String result = this.getPrepayId(contentMap);//调用统一接口返回的值
        Map<String, String> map = XMLUtil.doXMLParse(result);//调用统一接口返回的值转换为XML格式
        System.out.println(map);
        TreeMap<String, String> wxPayParamMap = new TreeMap<String, String>();
        wxPayParamMap.put("appId", appId);
        wxPayParamMap.put("nonceStr", nonceStr);
        wxPayParamMap.put("package", "prepay_id=" + map.get("prepay_id"));
        wxPayParamMap.put("signType", signType);
        wxPayParamMap.put("timeStamp", timeStamp);
        String paySign = createPaySign(wxPayParamMap);//支付得到的签名
        wxPayParamMap.put("paySign", paySign);
        logger.info("####生成的支付签名####paySign####" + paySign);

        String accessToken = getAccessToken("weixin");
        String ticket = getJsapiTicket(accessToken, "weixin");
        String signature = getSignature(ticket,settingService.getSettingInfo(SettingNameEnum.WXPAY_PAY_SIGN_URL), nonceStr);
        logger.info("####生成的支付签名####signature####" + signature);

        wxPayParamMap.put("signature", signature);
        wxPayParamMap.put("goodsName", sbf.substring(0, sbf.length() - 1).toString());
        return wxPayParamMap;
    }

    /**
     *  H5支付
     * @param request
     * @param orderVos
     * @param openid
     * @param orderBatchNumber
     * @return
     * @throws Exception
     */
    public Map<String, String> getH5PayParams(HttpServletRequest request, List<OrderVo> orderVos, String openid, String orderBatchNumber) throws Exception {

        BigDecimal total_fee = new BigDecimal(0);

        for(OrderVo orderVo:orderVos){
            total_fee =  total_fee.add(orderVo.getOrderAmount());
        }

        String appId = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID);
        String mchtId = settingService.getSettingInfo(SettingNameEnum.WXPAY_MCHT_ID);
        String notifyUrl = settingService.getSettingInfo(SettingNameEnum.WXPAY_NOTIFY_URL);
        String signType = settingService.getSettingInfo(SettingNameEnum.WXPAY_SIGN_TYPE);
        String tradeJs = settingService.getSettingInfo(SettingNameEnum.WXPAY_TRADE_TYPE_JS);
//        String ip = settingService.getSettingInfo(SettingNameEnum.WXPAY_SPBILL_CREATE_IP);
        String ip = getIp(request);
        String wxWebsite = settingService.getSettingInfo(SettingNameEnum.WXWEBSITE);

        String nonceStr = Sha1Util.getNonceStr();//随机字符串
        String timeStamp = Sha1Util.getTimeStamp();//时间戳
        List<OrderGoods> orderGoodsList = new ArrayList<OrderGoods>();
        StringBuffer sbf = new StringBuffer();
        for(OrderVo orderVo:orderVos){
            orderGoodsList.addAll(orderGoodsMapper.findOrderGoodsListByOrderId(orderVo.getOrderId())) ;

            for (OrderGoods orderGoods : orderGoodsList) {
                sbf.append(orderGoods.getGoodsName());
                sbf.append(",");
            }
        }

        // 接口package部分-内容----------------------------------------------------------
        TreeMap<String, String> contentMap = new TreeMap<String, String>();
        contentMap.put("appid", appId); // 公众账号 ID
        contentMap.put("mch_id", mchtId); // 商户号
        contentMap.put("nonce_str", nonceStr); // 随机字符串
        if(orderGoodsList.size()>1){
            contentMap.put("body", orderGoodsList.get(0).getGoodsName()+"……");
        }else if(orderGoodsList.size()==1){
            contentMap.put("body", orderGoodsList.get(0).getGoodsName());
        }else{
            contentMap.put("body", "goods");
        }
        contentMap.put("out_trade_no", orderBatchNumber+ getRandom()); // 商户订单号
        contentMap.put("total_fee", total_fee.multiply(new BigDecimal(100)).intValue() + ""); // 订单总金额
        contentMap.put("spbill_create_ip", ip); // 订单生成的机器IP
        contentMap.put("notify_url", notifyUrl); // 通知地址
        contentMap.put("trade_type", "MWEB"); // 交易类型
        String scene_info = "{\"h5_info\":{\"type\":\"Wap\",\"wap_url\":\"" + wxWebsite + "\",\"wap_name\":\"员工关爱\"}}";
        contentMap.put("scene_info", scene_info);
//        contentMap.put("openid", openid); // 用户标识
        String wxpackage = createPackage(contentMap);
        contentMap.put("sign", wxpackage);
        System.out.println(contentMap.toString() + "支付参数");
        logger.info("======支付参数:" + contentMap.toString());
        String result = this.getPrepayId(contentMap);//调用统一接口返回的值
        Map<String, String> map = XMLUtil.doXMLParse(result);//调用统一接口返回的值转换为XML格式
        System.out.println(map);
        logger.info("======map:" + map);
        String mwebUrl = map.get("mweb_url");
        System.out.println("mweb_url="+mwebUrl);
        logger.info("======mweb_url:" + mwebUrl);

        TreeMap<String, String> wxPayParamMap = new TreeMap<String, String>();
        wxPayParamMap.put("appId", appId);
        wxPayParamMap.put("mweb_url", mwebUrl);
        wxPayParamMap.put("goodsName", sbf.substring(0, sbf.length() - 1).toString());

        return wxPayParamMap;
    }

    // 商户订单号
    public static String getRandom() {
        String verifyCode = "";
        Random r = new Random();
        for (int i = 0; i < 4; i++) {
            verifyCode += r.nextInt(10);
        }
        return verifyCode;
    }

    /**
     * 创建支付包Package
     *
     * @param treeMap
     * @return
     */
    private String createPackage(TreeMap<String, String> treeMap) {
        String string1 = originalString(treeMap);
        String stringSignTemp = string1 + "key=" + settingService.getSettingInfo(SettingNameEnum.WXPAY_PARTNER_KEY);
        String sign = MD5Util.MD5Encode(stringSignTemp, settingService.getSettingInfo(SettingNameEnum.WXPAY_INPUT_CHARSET)).toUpperCase();
        return sign;
    }

    /**
     * 获取预支付id
     *
     * @param payParamMap
     * @return
     */
    private String getPrepayId(TreeMap<String, String> payParamMap) {

        String url = settingService.getSettingInfo(SettingNameEnum.WXPAY_PAY_INTERFACE);
        String charset = settingService.getSettingInfo(SettingNameEnum.WXPAY_INPUT_CHARSET);
        String result = HttpTool.sendPost(url, payParamMap, charset);
        return result;
    }

    /**
     * 创建支付签名paysign
     *
     * @return
     */
    private String createPaySign(TreeMap<String, String> param) {
        String string1 = originalString(param);
        String stringSignTemp = string1 + "key=" + settingService.getSettingInfo(SettingNameEnum.WXPAY_PARTNER_KEY);
        System.out.println("签名调试输出：" + stringSignTemp);
        String paysign = MD5Util.MD5Encode(stringSignTemp, settingService.getSettingInfo(SettingNameEnum.WXPAY_INPUT_CHARSET)).toUpperCase();
        return paysign;
    }

    @Override
    public String getAccessToken(String inMode) throws Exception {
        String access_token = null;
        String wx_access_token = redisService.getByKey("wx_access_token");
        String qy_access_token = redisService.getByKey("qy_access_token");

        if ("qiye".equals(inMode)) {
            //redis中没有access_token数据时，发送http请求获取
            if (StringUtils.isEmpty(qy_access_token)) {
                String appId = settingService.getSettingInfo(SettingNameEnum.WXCORPID);
                String appSecret = settingService.getSettingInfo(SettingNameEnum.WXCORPSECRET);
                String charset = settingService.getSettingInfo(SettingNameEnum.WXPAY_INPUT_CHARSET);
                String result = HttpTool.sendGet("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + appId + "&corpsecret=" + appSecret, charset);
                JSONObject jsonObject = JSONObject.fromObject(result);
                System.out.println(jsonObject.toString());
                access_token = jsonObject.getString("access_token");
                //缓存access_token到redis中
                redisService.setValueInTime("qy_access_token", access_token, 7200L);
            } else {
                access_token =  qy_access_token;
            }
        } else {
            //redis中没有access_token数据时，发送http请求获取
            if (StringUtils.isEmpty(wx_access_token)) {
                String appId = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_ID);
                String appSecret = settingService.getSettingInfo(SettingNameEnum.WXPAY_APP_SECRET);
                String charset = settingService.getSettingInfo(SettingNameEnum.WXPAY_INPUT_CHARSET);
                String result = HttpTool.sendGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret, charset);
                JSONObject jsonObject = JSONObject.fromObject(result);
                System.out.println(jsonObject.toString());
                access_token = jsonObject.getString("access_token");
                //缓存access_token到redis中
                redisService.setValueInTime("wx_access_token", access_token, 7200L);
            } else {
                access_token =  wx_access_token;
            }
        }

        return access_token;
    }

    @Override
    public String getJsapiTicket(String access_token, String inMode) throws Exception {
        String ticket = null;
        String wxTicket = redisService.getByKey("wx_jsapi_ticket");
        String qyTicket = redisService.getByKey("qy_jsapi_ticket");

        if ("qiye".equals(inMode)) {
            if (StringUtils.isEmpty(qyTicket)) {
                ticket = HttpTool.getQYJsTicket(access_token == null ? getAccessToken(inMode) : access_token);
                //缓存ticket
                redisService.setValueInTime("qy_jsapi_ticket", ticket, 7200L);
            } else {
                ticket =  qyTicket;
            }
        } else {
            if (StringUtils.isEmpty(wxTicket)) {
                ticket = HttpTool.getJsTicket(access_token == null ? getAccessToken(inMode) : access_token);
                //缓存ticket
                redisService.setValueInTime("wx_jsapi_ticket", ticket, 7200L);
            } else {
                ticket =  wxTicket;
            }
        }

        return ticket;
    }

    /**
     * 获取签名
     *
     * @param jsapi_ticket
     * @param url
     * @param nonceStr
     * @return
     * @throws Exception
     */
    private String getSignature(String jsapi_ticket, String url, String nonceStr) throws Exception {
        SortedMap<String, String> map = new TreeMap<String, String>();
        map.put("jsapi_ticket", jsapi_ticket);
        map.put("noncestr", nonceStr);
        map.put("timestamp", DateUtil.unixTimeStamp());
        map.put("url", url);
        return Sha1Util.createSHA1Sign(map);
    }

    /**
     * wxpackage组装原始串
     *
     * @param treeMap
     * @return
     */
    private String originalString(TreeMap<String, String> treeMap) {
        Set<Map.Entry<String, String>> entry = treeMap.entrySet();
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> obj : entry) {
            String k = obj.getKey();
            String v = obj.getValue();
            if (v == null && v.equals(""))
                continue;
            sb.append(k + "=" + v + "&");
        }
        return sb.toString();
    }

    // 获取用户真实IP（H5支付用）
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        System.out.println("x-forwarded-for ip: " + ip);
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
            System.out.println("Proxy-Client-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
            System.out.println("WL-Proxy-Client-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
            System.out.println("HTTP_CLIENT_IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
            System.out.println("X-Real-IP ip: " + ip);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            System.out.println("getRemoteAddr ip: " + ip);
        }
        return ip;
    }
}